#include "../logsys.h"
#include <chrono>


using namespace std;


//全局日志器建造者测试
void test_log(){
    //通过单例管理者获取指定日志器
    DEBUG("%s", "日志器测试开始");
    log::Logger::ptr plogger = log::LoggerManager::getInstance().getLogger("Async_logger");
    plogger->debug("%s", "日志器测试 -");
    plogger->info( "%s", "日志器测试 -");
    plogger->warning("%s", "日志器测试 -");
    plogger->error("%s", "日志器测试 -");
    plogger->fatal("%s", "日志器测试 -");
    size_t cnt = 0;
    while (cnt < 50000){
        plogger->fatal("日志器测试 - %d", cnt++);
        usleep(1000);
    }

    //宏标准输出，不用获取日志器
    FATAL("%s", "日志器测试结束");

}

//性能测试
void bench(const string &logger_name, size_t thr_cnt, size_t msg_cnt, size_t msg_len){
    //1、获取日志器
    log::Logger::ptr logger = log::getLogger(logger_name);
    if(logger.get() == nullptr){
        return;
    }

    cout << "测试日志：" << msg_cnt << "条，大小：" << (msg_len * msg_cnt) / 1024 << "KB" << endl;
    // 2、组织指定长度的日志消息
    string msg(msg_len - 1, 'A');   //少一个字节是为了给末尾添加换行
    msg += '\n';

    // 3、创建指定数量的线程
    vector<thread> threads;
    vector<double> cost_arr(thr_cnt);
    //每个线程的日志数量 = 总数 / 线程数
    size_t msg_cnt_pt = msg_cnt / thr_cnt;
    for (int i = 0; i < thr_cnt; i++){
        //push_back需要先创建对象再插入，emplace_back直接在vector的空间内创建对象
        threads.emplace_back([&,i](){
            // 4、在线程内部开始计时
            auto start = chrono::high_resolution_clock::now();

            // 5、写日志
            for (int j = 0; j < msg_cnt_pt; j++){
                logger->fatal("%s", msg.c_str());
            }
            // 6、线程内部结束计时
            auto end = chrono::high_resolution_clock::now();
            // 7、计算耗时
            chrono::duration<double> cost = end-start;
            cost_arr[i] = cost.count();
            cout << "thread no." << i << " 输出日志数量：" << msg_cnt_pt << " 耗时：" << cost.count() << "s" << endl;
        });
    }

    for (int i = 0; i < thr_cnt;i++){
        threads[i].join();
    }
    //7.2、计算总耗时，多线程并发，总耗时就是耗时最多的线程的耗时
    double max_cost = cost_arr[0];
    for (int i = 1; i < thr_cnt;i++){
        max_cost = max_cost < cost_arr[i] ? cost_arr[i] : max_cost;
    }

    size_t msg_cnt_ps = msg_cnt / max_cost;
    size_t size_ps = (msg_cnt * msg_len) / (max_cost * 1024);

    // 8、输出打印
    cout << "总耗时：" << max_cost << "s" << endl;
    cout << "每秒输出的日志数量：" << msg_cnt_ps << endl;
    cout << "每秒输出的大小" << size_ps << "KB" << endl;
}

void sync_bench(){
    cout << "Sync_logger" << endl;
    unique_ptr<log::LoggerBuilder> logbuilder(new log::GlobalLoggerBuilder());
    logbuilder->buildLoggerName("Sync_logger");
    logbuilder->buildLoggerType(log::LoggerType::SYNC);
    logbuilder->buildFormatter("%m%n");
    logbuilder->buildSink<log::FileSink>("log/sync.log");
    logbuilder->build();

    bench("Sync_logger", 3, 1000000, 100);

}

void async_bench(){
    cout << "Async_logger" << endl;
    unique_ptr<log::LoggerBuilder> logbuilder(new log::GlobalLoggerBuilder());
    logbuilder->buildLoggerName("Async_logger");
    logbuilder->buildLoggerType(log::LoggerType::SYNC);
    logbuilder->buildFormatter("%m%n");
    logbuilder->buildSink<log::FileSink>("log/async.log");
    logbuilder->setAsyncUnsafe();
    logbuilder->build();

    bench("Async_logger", 3, 1000000, 100);

}

int main(){


    // //format.hpp
    // log::LogMsg lmsg(log::LogLevel::value::INFO, "test.c", 66, "root", "format test...");
    // log::Formatter fmt;
    // string str = fmt.toFormat(lmsg);

    // // //sink.hpp
    // // log::LogSink::ptr psf_out = log::SinkFactory::createSink<log::outSink>();
    // // psf_out->writeLog(str.c_str(), str.size());

    // // log::LogSink::ptr psf_file = log::SinkFactory::createSink<log::FileSink>("log/testfile.log");
    // // psf_file->writeLog(str.c_str(), str.size());

    // // log::LogSink::ptr psf_roll_s = log::SinkFactory::createSink<log::RollSink_size>("log/roll_s_", 1024*1024);
    // // size_t cursize;
    // // size_t cnt;
    // // while(cursize<1024*1024*5){
    // //     string tmp = str + to_string(cnt++);
    // //     psf_roll_s->writeLog(tmp.c_str(), tmp.size());
    // //     cursize += tmp.size();
    // // }

    // log::LogSink::ptr psf_roll_t = log::SinkFactory::createSink<log::RollSink_time>("log/roll_t_", log::TimeGap::GAP_SECOND);
    // time_t ot = log::util::Date::getTime();
    // while (log::util::Date::getTime() < ot + 5)
    // {
    //     psf_roll_t->writeLog(str.c_str(), str.size());
    //     usleep(1000);
    // }


    //logger.hpp
    // string loggername = "SyncLogger";
    // log::LogLevel::value limit_level = log::LogLevel::value::WARNING;
    // log::Formatter::ptr pfmt(new log::Formatter("%d-%Y/%m/%d-%H:%M:%S [%t] [%p] [%c] [%f:%l] %T%m%n"));
    // log::LogSink::ptr psf_out = log::SinkFactory::createSink<log::outSink>();
    // log::LogSink::ptr psf_file = log::SinkFactory::createSink<log::FileSink>("log/testfile.log");
    // log::LogSink::ptr psf_roll_s = log::SinkFactory::createSink<log::RollSink_size>("log/roll_s-", 1024*1024);
    // vector<log::LogSink::ptr> sinks{psf_out, psf_file, psf_roll_s};

    // log::Logger::ptr plogger(new log::SyncLogger(loggername, limit_level, pfmt, sinks));

    // unique_ptr<log::LoggerBuilder> logbuilder(new log::LocalLoggerBuilder());
    // logbuilder->buildLoggerLevel(log::LogLevel::value::WARNING);
    // logbuilder->buildLoggerName("sync_logger");
    // logbuilder->buildLoggerType(log::LoggerType::SYNC);
    // logbuilder->buildFormatter("%m%n");
    // logbuilder->buildSink<log::outSink>();
    // logbuilder->buildSink<log::FileSink>("log/testfile.log");
    // logbuilder->buildSink<log::RollSink_size>("log/roll_s-", 1024*1024);

    // log::Logger::ptr plogger = logbuilder->build();

    // plogger->debug(__FILE__, __LINE__, "%s", "日志器测试 -");
    // plogger->info(__FILE__, __LINE__, "%s", "日志器测试 -");
    // plogger->warning(__FILE__, __LINE__, "%s", "日志器测试 -");
    // plogger->error(__FILE__, __LINE__, "%s", "日志器测试 -");
    // plogger->fatal(__FILE__, __LINE__, "%s", "日志器测试 -");

    // size_t cursize;
    // size_t cnt;
    // while (cursize < 1024 * 1024 * 5)
    // {
    //     // string tmp = str + to_string(cnt++);
    //     plogger->fatal(__FILE__, __LINE__, "日志器测试 - %d", cnt++);
    //     cursize += 20;
    // }


    // //buffer.hpp
    // //1、读取文件数据，依次写入缓冲区（让缓冲区不断扩容）
    // ifstream ifs("./log/testfile.log", ios::binary);
    // if(!ifs.is_open()){
    //     cerr << "open err" << endl;
    //     return -1;
    // }
    // //读写位置跳转到文件末尾
    // ifs.seekg(0, ios::end);
    // //获取当前读写位置相较于起始位置的偏移量 -- 获取文件长度
    // size_t fsize = ifs.tellg();
    // //读写位置回到起始位置
    // ifs.seekg(0, ios::beg);
    // string body;
    // body.resize(fsize);
    // //不能用body.c_str()，因为body.c_str()返回的是const，不能修改
    // ifs.read(&body[0], fsize);
    // if(!ifs.good()){
    //     cerr << "read err" << endl;
    //     return -1;
    // }
    // ifs.close();

    // log::Buffer buf;

    // for (int i = 0; i < body.size();i++){
    //     buf.push(&body[i], 1);
    // }

    // // 2、创建一个新文件，把缓冲区的数据写入到新文件中
    // ofstream ofs("./log/tmp.log", ios::binary);
    // // ofs.write(buf.getBegin(), buf.readableSize());
    // //当buf中还有可读数据，进行读取
    // while(buf.readableSize()){
    //     //把读到的数据写到ofs中
    //     ofs.write(buf.getBegin(), 1);
    //     //写完后可读位置后移
    //     buf.moveRidx(1);
    // }
    // ofs.close();

    // //3、判断生成的新文件是否与原文件一致


    // //logger.hpp looper.hpp
    // unique_ptr<log::LoggerBuilder> logbuilder(new log::LocalLoggerBuilder());
    // logbuilder->buildLoggerLevel(log::LogLevel::value::WARNING);
    // logbuilder->buildLoggerName("Async_logger");
    // logbuilder->buildLoggerType(log::LoggerType::ASYNC);
    // logbuilder->buildFormatter("[%c]%m%n");
    // logbuilder->buildSink<log::outSink>();
    // logbuilder->buildSink<log::FileSink>("log/async.log");
    // logbuilder->buildSink<log::RollSink_size>("log/roll_s_", 1024 * 1024);
    // // //不安全的写入可能会导致内存耗尽数据丢失
    // // logbuilder->setAsyncUnsafe();

    // log::Logger::ptr plogger = logbuilder->build();

    // plogger->debug(__FILE__, __LINE__, "%s", "日志器测试 -");
    // plogger->info(__FILE__, __LINE__, "%s", "日志器测试 -");
    // plogger->warning(__FILE__, __LINE__, "%s", "日志器测试 -");
    // plogger->error(__FILE__, __LINE__, "%s", "日志器测试 -");
    // plogger->fatal(__FILE__, __LINE__, "%s", "日志器测试 -");

    // // size_t cursize = 0;
    // // size_t cnt = 0;
    // // while (cursize < 1024 * 1024 * 5)
    // // {
    // //     // string tmp = str + to_string(cnt++);
    // //     plogger->fatal(__FILE__, __LINE__, "日志器测试 - %d", cnt++);
    // //     cursize += 20;
    // // }

    // //有两个问题：
    // //  1、不能精准规定每个日志文件的大小
    // //      当缓冲区中有较多数据，但当前日志文件小于指定大小时，会把缓冲区中的数据全部写入当前日志文件，这样就造成了每个日志文件超过指定大小
    // //  2、可能会存在漏写
    // //      当main结束之后，可能生产缓冲区中还有数据尚未被递交给工作线程，main结束调用析构函数清理生产缓冲区，会造成数据丢失
    // //      解决方法：在对缓冲区数据进行处理的工作线程中添加对生产缓冲区是否为空的判断，
    // //              不为空就不退出，循环交换缓冲区对数据进行处理，直到处理完数据再次交换前检测到生产缓冲区为空再退出
    // size_t cnt = 0;
    // while (cnt < 500000){
    //     plogger->fatal(__FILE__, __LINE__, "日志器测试 - %d", cnt++);
    // }

    

    // // //全局日志器建造者测试
    // unique_ptr<log::LoggerBuilder> logbuilder(new log::GlobalLoggerBuilder());
    // logbuilder->buildLoggerLevel(log::LogLevel::value::WARNING);
    // logbuilder->buildLoggerName("Async_logger");
    // logbuilder->buildLoggerType(log::LoggerType::ASYNC);
    // logbuilder->buildFormatter("[%c][%f:%l]%m%n");
    // logbuilder->buildSink<log::outSink>();
    // logbuilder->buildSink<log::FileSink>("log/async.log");
    // logbuilder->buildSink<log::RollSink_size>("log/roll_s_", 1024 * 1024);
    // logbuilder->buildSink<log::RollSink_time>("log/roll_t_", log::TimeGap::GAP_SECOND);
    // //这里不用获取logger是因为GlobalBuilder已经将所生成的logger添加给全局日志器管理者了，通过管理者进行调用就行
    // logbuilder->build();

    // test_log();
    // // log::Logger::ptr plogger = log::LoggerManager::getInstance().getLogger("Async_logger");
    // // plogger->debug(__FILE__, __LINE__, "%s", "日志器测试 -");
    // // plogger->info(__FILE__, __LINE__, "%s", "日志器测试 -");
    // // plogger->warning(__FILE__, __LINE__, "%s", "日志器测试 -");
    // // plogger->error(__FILE__, __LINE__, "%s", "日志器测试 -");
    // // plogger->fatal(__FILE__, __LINE__, "%s", "日志器测试 -");
    // // size_t cnt = 0;
    // // while (cnt < 500000){
    // //     plogger->fatal(__FILE__, __LINE__, "日志器测试 - %d", cnt++);
    // // }

    sync_bench();
    async_bench();
    return 0;
}